﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;

using IrisGenerator.Framework.Messaging;
using IrisGenerator.Framework.RuleEngine;


namespace IrisGenerator.Common.Core
{

    public class ConnectedCollectionBase<T> : BindingList<T>, IMessageSender<T> where T:IRuleable<T>,IBindableObject
    {
       
        #region Fields

        private bool _adding = false;
        private bool _removing = false;

        #endregion

        #region Events

        #region IMessageSender Members

        /// <summary>
        /// Event to fire a message to a GUI.
        /// </summary>
        public event EventHandler<MessageEventArgs<T>> MessageSend;
        
        /// <summary>
        /// Method implemented to raise the MessageSend event.
        /// </summary>
        /// <param name="e">The argument passed when firing the event.</param>
        public virtual void OnMessageSend(MessageEventArgs<T> e)
        {
            if (MessageSend != null)
                MessageSend(this, e);
        }

        #endregion

        #endregion

        #region Overrides

        protected override void OnAddingNew(AddingNewEventArgs e)
        {
            //T item =(T)e.NewObject;

            //if (item == null)
            //    return;

            //IDbBindableObjectRules ruleChecker = item.Rules as IDbBindableObjectRules;
            //RuleErrorCollection returnValue = null;
            //if (ruleChecker != null && ruleChecker.CanInsert(ref returnValue))
            //{
            //    item.Insert();
            //    _adding = false;
            //    SetMessageHandler(item);
            //    base.OnAddingNew(new AddingNewEventArgs(item));
            //}
            _adding = true;
        }

        protected override void InsertItem(int index, T item)
        {
            SetMessageHandler(item);
            base.InsertItem(index, item);
        }

        /// <summary>
        /// Removes an item from the collection. The method is called when deleting an item from a binded control for instance.
        /// </summary>
        /// <remarks>The item is only removed if the call to the delete method of the underlying object succeeds.</remarks>
        /// <param name="index">The index of the item that is deleted.</param>
        protected override void RemoveItem(int index)
        {
                        
                if (index < 0 || index > this.Count - 1)
                    return;

                if (_adding)
                {
                    RemoveMessageHandler(this[index]);
                    base.Items.RemoveAt(index);
                    _adding = false;
                }
                else if (this.Items[index].Delete(true))
                {

                    _removing = true;
                    _adding = false;
                    RemoveMessageHandler(this[index]);
                    base.Items.RemoveAt(index);
                    
                    this.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
                }

                
        }

        /// <summary>
        /// Method called when a property of an item of the underlying connection occures.
        /// </summary>
        /// <param name="e">Parameter to know which action was made.</param>
        ///<remarks>The items are inserted only when an item is added and can be inserted in the underlying store.
        /// If the object is binded to a table and that constraints are not respected, the object is not added until all constraints can apply.
        /// </remarks>
        protected override void OnListChanged(ListChangedEventArgs e)
        {
            if (e.ListChangedType == ListChangedType.ItemChanged)
            {

                T tmp = this.Items[e.NewIndex];
                RuleErrorCollection returnValue=null;

                IDbBindableObjectRules ruleChecker = tmp.Rules as IDbBindableObjectRules;
                if (ruleChecker != null && _adding && ruleChecker.CanInsert(ref returnValue))
                {
                    tmp.Insert();
                    _adding = false;
                }
                else
                {
                    if (!_adding)
                        tmp.Update();
                    
                }
            }
            base.OnListChanged(e);
        }

        void obj_MessageSend(object sender, MessageEventArgs<T> e)
        {
            this.OnMessageSend(e);
        }


        #endregion

        #region ctor

        /// <summary>
       /// .ctor
       /// </summary>
        public ConnectedCollectionBase():base(new List<T>())
        {
            //this.ListChanged += new ListChangedEventHandler(MetatypeCollection_ListChanged);
            _adding = false;
            
        }

        /// <summary>
        /// .ctor
        /// </summary>
        /// <param name="col">The base collection that is used to fill the inner collection.</param>
        public ConnectedCollectionBase(IList<T> col)
            : base(col)
        {
            foreach (T obj in col)
                SetMessageHandler(obj);

         
        }

        #endregion

        #region Event Handling

        /// <summary>
        /// Method handling messages sent from the metatypes objects in the collection
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ObjectRules_SendMessage(object sender, MessageEventArgs<T> e)
        {
            this.OnMessageSend(e);
        }

        #endregion

        #region Methods

        private void SetMessageHandler(T obj)
        {
            IMessageSender<T> tmp = obj as BindableObject<T>;

            if (tmp != null)
                tmp.MessageSend += new EventHandler<MessageEventArgs<T>>(obj_MessageSend);
            
        }

        private void RemoveMessageHandler(T obj)
        {
            IMessageSender<T> tmp = obj as BindableObject<T>;

            if (tmp != null)
                tmp.MessageSend -= obj_MessageSend;
            
        }
        #endregion
    }

}
